package com.filldream.fastboot.core.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.filldream.fastboot.base.entity.QuartzJob;
import com.filldream.fastboot.base.entity.QuartzLog;
import com.filldream.fastboot.base.mapper.ScheduleJobMapper;
import com.filldream.fastboot.base.mapper.SysQuartzLogMapper;
import com.filldream.fastboot.base.request.pc.job.JobLogPageSTO;
import com.filldream.fastboot.common.exception.GlobalException;
import com.filldream.fastboot.core.cache.CacheUtil;
import com.filldream.fastboot.core.job.quartz.QuartzManage;
import com.filldream.fastboot.core.service.ScheduleJobService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.quartz.CronExpression;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;

/**
 * @author RickSun
 * @Description ScheduleJobServiceImpl
 **/
@RequiredArgsConstructor
@Service("scheduleJobService")
@Transactional(rollbackFor = Exception.class)
public class ScheduleJobServiceImpl extends ServiceImpl<ScheduleJobMapper, QuartzJob> implements ScheduleJobService {

    private final QuartzManage quartzManage;

    private final SysQuartzLogMapper jobLogMapper;

    @Override
    public void add(QuartzJob resources) {
        if (!CronExpression.isValidExpression(resources.getCronExpression())){
            throw new GlobalException("cron表达式格式错误");
        }
        baseMapper.insert(resources);
        quartzManage.addJob(resources);
    }

    @Override
    public void modify(QuartzJob resources) {
        if (!CronExpression.isValidExpression(resources.getCronExpression())){
            throw new GlobalException("cron表达式格式错误");
        }
        if(StringUtils.isNotBlank(resources.getSubTask())){
            List<String> tasks = Arrays.asList(resources.getSubTask().split("[,，]"));
            if (tasks.contains(resources.getId().toString())) {
                throw new GlobalException("子任务中不能添加当前任务ID");
            }
        }
        baseMapper.updateById(resources);
        quartzManage.updateJobCron(resources);
    }

    @Override
    public void delete(List<Long> ids) {
        for (Long id : ids) {
            QuartzJob quartzJob = getById(id);
            quartzManage.deleteJob(quartzJob);
            baseMapper.deleteById(id);
        }
    }

    @Async
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void executionSubJob(String[] tasks) throws InterruptedException {
        for (String id : tasks) {
            if (StrUtil.isBlank(id)) {
            // 如果是手动清除子任务id，会出现id为空字符串的问题
            continue;
            }
            QuartzJob quartzJob = baseMapper.selectById(Long.parseLong(id));
            // 执行任务
            String uuid = IdUtil.simpleUUID();
            quartzJob.setUuid(uuid);
            // 执行任务
            execution(quartzJob);
            // 获取执行状态，如果执行失败则停止后面的子任务执行
            String result = CacheUtil.getStr(uuid);
            while (StringUtils.isBlank(result)) {
                // 休眠5秒，再次获取子任务执行情况
                Thread.sleep(5000);
                result =  CacheUtil.getStr(uuid);
            }
            if(!(result == "1")){
                CacheUtil.delKey(uuid);
                break;
            }
        }
    }

    @Override
    public void execution(QuartzJob quartzJob) {
                quartzManage.runJobNow(quartzJob);
        }

    @Override
    public void updateIsPause(QuartzJob quartzJob) {
        if (quartzJob.getIsPause() == 0) {
            quartzManage.resumeJob(quartzJob);
            quartzJob.setIsPause(1);
        } else {
            quartzManage.pauseJob(quartzJob);
            quartzJob.setIsPause(0);
        }
        baseMapper.updateById(quartzJob);
    }

    @Override
    public Page<QuartzLog> jobLogPage(JobLogPageSTO sto) {

        LambdaQueryWrapper<QuartzLog> sql = new LambdaQueryWrapper<>();
        if( StringUtils.isNotBlank(sto.getKeyContent()) ){
            sql.and( (eq ->
                    eq.like(QuartzLog::getBeanName,sto.getKeyContent())
                            .or()
                            .like(QuartzLog::getJobName,sto.getKeyContent())
                            .or()
                            .like(QuartzLog::getMethodName,sto.getKeyContent())
            ) );
        }
        if( sto.getIsSuccess() != null ){
            sql.eq(QuartzLog::getIsSuccess,sto.getIsSuccess());
        }

        if( sto.getCreateTimeStart() != null ){
            sql.ge(QuartzLog::getCreateTime,sto.getCreateTimeStart());
        }
        if( sto.getCreateTimeEnd() != null ){
            sql.le(QuartzLog::getCreateTime,sto.getCreateTimeEnd());
        }

        sql.orderByDesc(QuartzLog::getCreateTime);
        return jobLogMapper.selectPage(sto.page(), sql);
    }

    @Override
    public QuartzLog getJobLog(Long id) {
        return jobLogMapper.selectById(id);
    }

    @Override
    public Boolean clearJobLog() {
        return jobLogMapper.delete(new LambdaQueryWrapper<>()) > 0;
    }

    @Override
    public void init(String notBeanName) {
        List<QuartzJob> list = baseMapper.selectList(
                new LambdaQueryWrapper<QuartzJob>().eq(QuartzJob::getIsPause, 1)
                        .ne(QuartzJob::getBeanName,notBeanName)
        );
        for (QuartzJob item : list) {
            quartzManage.addJob( item );
        }
    }

}